□ BLE 메시지(Version 2)

o 메시지 형식

Q=<MessageCode>;<Version>;<DeviceType>;<DeviceID>;<Message>;<SeqNo>

구 분	설 명	비 고
MessageCode	o 0 : 상태 메시지 o 1 : 연결 메시지 o 2 : 격발 메시지 o 5 : 동작 메시지
Version	o ‘2’를 사용
DeviceType	o 1 : 추락보호복 o 2 : 노인낙상
DeviceID	o 디바이스 고유번호	SWYYMMTNNNNN
Message	o 각 메시지별 상이
SeqNo	o 메시지 일련번호	0 ∼ 999

【연결 메시지】

o BLE 접속時 1회 전송

o 메시지 내용

<CPUID>,<VersionInfo>,<BootResult>,<BatteryValue>

구 분	설 명	비 고
CPUID	o MCU 고유번호
VersionInfo	o 펌웨어 버전
BootResult	o 센서보드 부팅 결과	16진수 스트링
BatteryValue	o 배터리 레벨

o 오류 감지時 BootResult 설정값

#define SYS_INIT_FAULT_GPIO         0x00000001

#define SYS_INIT_FAULT_DMA          0x00000002

#define SYS_INIT_FAULT_UART         0x00000004

#define SYS_INIT_FAULT_ADC          0x00000008

#define SYS_INIT_FAULT_TWI          0x00000010  // I2C

#define SYS_INIT_FAULT_TIMER        0x00000020

#define SYS_INIT_FAULT_SPI          0x00000040

#define SYS_INIT_FAULT_QSPI         0x00000080

#define SYS_INIT_FAULT_RTC          0x00000100

#define SYS_INIT_FAULT_FLASH        0x00000200

#define SYS_INIT_FAULT_IMU          0x00000400

#define SYS_INIT_FAULT_BATTERY      0x00000800

#define SYS_INIT_FAULT_BUZZER       0x00001000

#define SYS_INIT_FAULT_W25Q         0x00002000

#define SYS_INIT_FAULT_TICK         0x00004000

#define SYS_INIT_FAULT_ACTUATOR     0x00008000

#define SYS_INIT_FAULT_BLE          0x00010000

#define SYS_INIT_FAULT_UPSIDE_DOWN  0x80000000

【상태 및 격발 메시지】

o 상태 메시지는 1분마다, 격발 메시지는 추락이나 낙상 검출時 전송

o 메시지 내용

<Trigger>,<Battery>,<Actuator>,<IMU>,<Flash>

구 분	설 명	비 고
Trigger	o 격발 유형	0 : 未격발
Battery	o 배터리 레벨	백분율 표시
Actuator	o Actuator 연결 상태	0 : 정상, 1 : 장애
IMU	o IMU 센서 오류 횟수
Flash	o 플래쉬 오류 횟수

【동작 메시지】

o 5분마다 위험도(5분 동안의 최댓값)를 전송

o 메시지 내용

0,<Risk>

구 분	설 명	비 고
Risk	o 위험도 수치	백분율 표시

□ 사용자 앱 동작

【BLE 메시지 처리】

o 스마트폰 앱은 블루투스를 통해 수신한 BLE 메시지를 MQTT 서버로 전달

o 격발 메시지를 수신한 경우, 수신한 BLE 메시지에 GPS 및 주소 정보를 첨부한 후 MQTT 서버로 전달

Q=2;2;2;<DeviceID>;<Message>;SeqNo;<Lattitude>,<Longitude>;<Location>;<Address>

* BLE를 통해 센서보드로 ‘ack 2’를 전송, 격발 메시지 재전송 차단

o 연결 메시지의 BootResult가 ‘00000000’이 아닌 경우, 값에 따라 경고창을 표시하고 음성 메시지를 출력

o 상태 메시지의 Battery가 30 미만인 경우, 경고창을 표시하고 음성 메시지를 출력

o 상태 메시지의 Actuator⋅IMU⋅Flash가 ‘0’이 아닌 경우, 경고창을 표시하고 음성 메시지 및 진동을 출력

【디바이스 최초 등록】

o 연결 메시지의 DeviceID가 ‘XXX’인 경우, 디바이스 최초 등록 절차를 실시

o 최초 등록 절차

-  (스마트폰) CPUID⋅VersionInfo⋅BLEID를 포함하여 디바이스 등록 REST API(/api/down/devices)를 호출

- (서버) CPUID⋅VersionInfo⋅BLEID를 DB에 등록하고 DeviceID를 생성하여 REST API 응답으로 전달

-  (스마트폰) ‘set id <DeviceID>’ 명령어를 BLE를 통해 센서보드에 전달, 수신한 DeviceID를 센서보드에 기록

□ MQTT 메시지(스마트폰 → 서버)

【일반사항】

o MQTT 토픽 : D1

【사용자 및 보호자 등록】

o 사용자 등록

Q=9;2;2;<DeviceID>;0,<TelNo>,<TokenKey>;0

* 사용자 등록時 서버내 旣등록 보호자 정보 삭제

* TokenKey : 32 바이트 랜덤 스트링

o 사용자 전환

Q=9;2;2;<DeviceID>;1,<TelNo>,<TokenKey>;0

* 사용자 전환時 서버내 旣등록 보호자 정보 유지

o 보호자 등록

Q=9;2;2;<DeviceID>;2,<TelNo>,<Type>;0

구 분	설 명	비 고
Type	o 0 : SMS만 수신 o 1 : 보호자 앱 모드

【보호자 : 보호자 등록】

o 보호자 등록

Q=9;2;2;<DeviceID>;3,<TelNo>,<Type>;0

구 분	설 명	비 고
Type	o 0 : SMS만 수신 o 1 : 보호자 앱 모드	사용자 동의 未확인 사용자 동의 확인

【만보기 데이터 전송】

o 걸음수⋅칼로리 등 만보기 데이터를 30분마다 MQTT 서버로 전송

Q=5;2;2;<DeviceID>;1,<Walk>,<Calory>,<Span>;0

* Span : 운동시간, 초 단위

【위치 정보 전송】

o 위치 정보를 5분마다 MQTT 서버로 전송

Q=5;2;2;<DeviceID>;2,<Latitude>,<Longitude>[;<위치명칭>;<주소>];0

* 위치명칭이 이전(위치 정보 메시지)과 동일한 경우, 위치명칭과 주소는 생략

【DFU 진행상황 통보】

o 펌웨어 업데이트 진행時 시작⋅종료⋅오류 등 진행상황 통보

o DFU 시작

Q=3;2;2;<DeviceID>;1,<firmware_filename>,<file_length>;0

o DFU 종료(펌웨어 업데이트 성공時)

Q=3;2;2;<DeviceID>;2,<firmware_filename>,<file_length>;0

o DFU 오류(펌웨어 업데이트 도중 오류 발생時)

Q=3;2;2;<DeviceID>;4,<firmware_filename>,<진행률(퍼센트)>;0

□ MQTT 메시지(서버 → 스마트폰)

【일반사항】

o MQTT 토픽 : TS/<DeviceID>

【보호자 등록】

o 보호자가 보호자 추가 등록을 요청할 때, 사용자의 동의를 확인한 후 보호자 추가 등록을 진행

Q=9;2;2;<DeviceID>;3,<TelNo>,<Type>;0

구 분	설 명	비 고
Type	o 1 : 보호자 앱 모드

* 사용자 동의 확인時‘Q=9;2;2;<DeviceID>;2,<TelNo>,<Type>;0’를 서버로 전송

【DFU 개시】

o 펌웨어 업데이트 필요時 DFU 개시를 명령

Q=3;2;2;<DeviceID>;0,<firmware_filename>,<file_length>;0

□ REST API

【등록 및 로그인】

o 디바이스 등록

- 기능 : 디바이스를 등록하고 생성한 DeviceID를 전달

- URL : /api/sw/device

- 모드 : POST

- 전달 데이터

{

“id” :　“XXX”,

“type” : 2,

“hw” : “{CPUID}”,

“sw” : “{VersionInfo}”,

“ble” : “{BLEID}”

}

- 응답 형식 : application/json

- 응답 데이터

{

“id” : “SW2405D00001”

}

o 로그인 토큰 확인

- URL : /api/sw/token/cache/:6digit?tkey={TokenKey}

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

{

"token“ : ”{TokenString}“

}

o 사용자 로그인

- 기능 : 토큰을 기반으로 사용자 로그인

- URL : /api/sw/token/login/:token

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

200 OK

{

“id” : “{DeviceID}”,

“tel” : “{TelNo}”,

“mode” : 0 || 1

}

* 0 : 사용자, 1 : 보호자

404 Not Found

{

“message” : "User with token <token_string>, not found."

}

o 사용자 로그오프

- 기능 : 토큰을 기반으로 사용자 로그오프

- URL : /api/sw/token/logoff/:token

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

200 OK

{

“id” : “{DeviceID}”,

“tel” : “{TelNo}”,

“mode” : 0 || 1

}

* 0 : 사용자, 1 : 보호자

404 Not Found

{

“message” : "User with token <token_string>, not found."

}

【각종 정보 검색】

o 각종 정보 검색 API 호출時 필요사항

- HTTP Authorization 헤더에 ‘Bearer {TokenString}’을 설정하여 REST API를 호출해야 하며,

- 각 REST API는 해당 기능 수행에 앞서 ‘TokenString’을 기준으로 사용자의 로그인 여부를 점검함

o 사용자 목록 확인

- 기능 : 동일 ID로 등록된 사용자 목록 확인

- URL : /api/sw/token/user

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

{

{

"tel": "01012345678",

"mode": 0,

"login": 1,

"dt": "20240626"

},

{

"tel": "01023456789",

"mode": 1,

"login": 0,

"dt": null

}

}

* mode : 0 → 사용자, 1 → 보호자, 2 → 보호자(SMS 수신만)

* login : 0 → logoff, 1 → login

o 사용자 등록 삭제

- 기능 : 전화번호 기준 사용자 등록 삭제

- URL : /api/sw/token/user/:tel

- 모드 : DELETE

- 응답 형식 : text/plain

- 응답 데이터

200 OK

o 현재 상태정보 확인

- 기능 : 위험도⋅만보기 등 현재 상태정보 확인

- URL : /api/down/state/:id

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

{

“dt” : “20240625 120101”,

“gps” : “<latitude>,<longitude>”,

“address” : “<address>”

“location” : “<location>”,

"risk“ : 80,

“walk” : 5000,

“cal” : 150,

“span” : 3800

}

o 디바이스 상태정보 확인

- 기능 : 배터리 등 디바이스 상태정보 확인

- URL : /api/sw/state/:id

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

{

“battery” : 90

}

o 일자별 위험도 확인

- 기능 : 최근 14일간의 일자별 위험도 데이터를 확인

- URL : /api/down/risk/date/:id

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

{

{

"dt : “20240425”,

“risk” : 50

},

⋅⋅⋅

{

"dt : “20240508”,

“risk” : 70

}

}

o 특정 일자 위험도 확인

- 기능 : 지정한 날짜의 5분 단위 위험도 데이터를 확인

- URL : /api/down/risk/data/:id[?qrdate=20240508]

* ‘qrdate’를 생략하면 오늘 데이터를 확인

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

{

{

“dt” : “0000”,

“risk” : 50

},

⋅⋅⋅

{

“dt” : “2355”,

“risk” : 30

}

}

o 일자별 만보기 데이터 확인

- 기능 : 최근 14일간의 일자별 만보기 데이터(걸음수, 칼로리)를 확인

- URL : /api/down/walk/date/:id

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

{

{

"dt : “20240425,

“walk” : 5000,

“cal” : 150,

“span” : 7500

},

⋅⋅⋅

{

"dt : “20240508”,

“walk” : 5000,

“cal” : 150,

“span” : 3600

}

}

o 특정 일자 만보기 데이터 확인

- 기능 : 지정한 날짜의 30분 단위 만보기 데이터(걸음수, 칼로리)를 확인

- URL : /api/down/walk/data/:id[?qrdate=20240508]

* ‘qrdate’를 생략하면 오늘 데이터를 확인

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

{

{

“dt” : “0000”,

“walk” : 5000,

“cal” : 150,

“span” : 500

},

⋅⋅⋅

{

“dt” : “2355”,

“walk” : 5000,

“cal” : 150,

“span” : 1500

}

}

o 사고 건수 확인

- URL : /api/sw/accident/count/:id

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

{

“result” : <count>

}

o 사고 기록 확인

- URL : /api/sw/accident/data/:id

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

{

{

“dt” : “20240508”,

“gps” : “{latitude},{longitude}”

“location” : “{location_string}”,

“address” : “{address_string}”

},

⋅⋅⋅

{

“dt” : “20240508”,

“gps” : “{latitude},{longitude}”

“location” : “{location_string}”,

“address” : “{address_string}”

}

}

o 최근 방문지 확인

- URL : /api/sw/location/recent/:id

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터

{

{

“dt” : “20240625 120101”,

“address” : “{address_string}”

},

⋅⋅⋅

{

“dt” : “20240625 110101”,

“address” : “{address_string}”

}

}

【각종 데이터 전달】

o Trigger Data 전달

- 기능 : 낙상 발생時 Trigger Data를 서버에 전달

- URL : /api/sw/tdata/:id

- 모드 : POST

- Content-Type : application/octet-stream

- 전달 데이터 : 바이너리 바이트 스트림

- 응답 데이터 : HTTP 응답

o DFU 펌웨어 파일 다운로드

- 기능 : 서버에서 펌웨어 파일을 다운로드

- URL : /api/sw/dfu/file/:id[?file={filename}]

- 모드 : GET

- Content-Type : application/octet-stream

- 응답 데이터 : 바이너리 바이트 스트림

o DFU 펌웨어 정보 확인

- URL : /api/sw/dfu/info/:id

- 모드 : GET

- 응답 형식 : application/json

- 응답 데이터 : 바이너리 바이트 스트림

{

“dfu” : 0 or 1

“file” : “D1-NRF-1.0.0-20240930”,

“len” : 144125,

“dt” : “20240625 120101”

}

* dfu : 0 → 업데이트 불필요, 1 → 업데이트 필요

□ 데이터베이스

【일반 사항】

o 호 스 트 : safewaredata.co.kr

o DB 버전 : MariaDB-10.6.3

o DB 명칭 : safeware_db

【테이블】

o sw_device

구분	유형	조건	비고
id	VARCHAR(32)	기본키	디바이스 ID
type	INT	NOT NULL
hw	VARCHAR(32)	“
sw	VARCHAR(32)	“
ble	VARCHAR(32)	“
dt	DATETIME	“	CURRENT_TIMESTAMP

o sw_token

구분	유형	조건	비고
token	VARVHAR(128)	기본키
id	VARCHAR(32)	NOT NULL	디바이스 ID
tel	VARCHAR(20)	“
mode	INT	“
dt_insert	DATETIME	“	CURRENT_TIMESTAMP
dt_login	DATETIME	NULL

o sw_token_cache

구분	유형	조건	비고
skey	VARVHAR(16)	기본키
id	VARCHAR(32)	NOT NULL
tkey	VARCHAR(64)	NULL
token	VARCHAR(128)	NOT NULL
dt	DATETIME	“	CURRENT_TIMESTAMP

o sw_sms_group

구분	유형	조건	비고
id	VARVHAR(32)	기본키
grpname	VARCHAR(32)	NOT NULL
dt	DATETIME	“	CURRENT_TIMESTAMP

o sw_sms_receiver

구분	유형	조건	비고
grpname	VARVHAR(32)	기본키
tel	VARCHAR(32)	기본키
dt	DATETIME	NOT NULL	CURRENT_TIMESTAMP

o sw_mqtt_message

구분	유형	조건	비고
id	VARVHAR(32)	기본키
dt	DATETIME	기본키	CURRENT_TIMESTAMP
qos	INT	기본키
topic	VARCHAR(100)	NULL
message	VARCHAR(100)	“

o sw_location

구분	유형	조건	비고
id	VARCHAR(32)	기본키	디바이스 ID
dt	DATETIME	기본키	CURRENT_TIMESTAMP
gps	VARCHAR(32)	NOT NULL	위도,경도
location	VARCHAR(100)	NULL	위치 명칭
address	VARCHAR(200)	NULL

o sw_accident

구분	유형	조건	비고
id	VARCHAR(32)	기본키	디바이스 ID
dt	DATETIME	기본키	CURRENT_TIMESTAMP
mode	INT	NOT NULL	검출 모드
gps	VARCHAR(32)	NOT NULL	위도,경도
location	VARCHAR(100)	NULL	위치 명칭
address	VARCHAR(200)	NULL

o sw_mqtt_link

구분	유형	조건	비고
id	VARVHAR(32)	기본키
mode	INT	NOT NULL
url	VARCHAR(256)	“
dt	DATETIME	“	CURRENT_TIMESTAMP

o sw_tdata

구분	유형	조건	비고
num	INT	기본키	AUTO_INCREMENT
id	VARVHAR(32)	NOT NULL
filepath	VARCHAR(256)	“
dt	DATETIME	“	CURRENT_TIMESTAMP

o down_walk_data

구분	유형	조건	비고
id	VARCHAR(32)	기본키	디바이스 ID
dt	DATETIME	기본키	CURRENT_TIMESTAMP
walk	int	NOT NULL
cal	int	NOT NULL
span	int	NOT NULL	운동시간

o down_date_walk

구분	유형	조건	비고
id	VARCHAR(32)	기본키	디바이스 ID
dt	DATE	기본키	CURDATE()
walk	int	NOT NULL
cal	int	NOT NULL
span	int	NOT NULL	운동시간

o down_risk_data

구분	유형	조건	비고
id	VARCHAR(32)	기본키	디바이스 ID
dt	DATETIME	기본키	CURRENT_TIMESTAMP
risk	int	NOT NULL	위험도, 백분율

o down_date_risk

구분	유형	조건	비고
id	VARCHAR(32)	기본키	디바이스 ID
dt	DATE	기본키	CURDATE()
risk	int	NOT NULL	위험도, 백분율

【트리거】

o after_insert_down_walk_data

DELIMITER //

CREATE TRIGGER after_insert_down_walk_data

AFTER INSERT ON down_walk_data

FOR EACH ROW

BEGIN

-- In case a record with the same value of 'id' & 'dt' exists in the table of 'down_date_walk',

-- it adds new values to that record.

UPDATE down_date_walk

SET walk = walk + NEW.walk, cal = cal + NEW.cal, span = span + NEW.span

WHERE id = NEW.id AND dt = DATE(NEW.dt);

-- In case a record with the same value of 'id' & 'dt' doesn't exist in the table of 'down_date_walk',

-- it inserts a new record.

IF ROW_COUNT() = 0 THEN

INSERT INTO down_date_walk (id, dt, walk, cal, span)

VALUES (NEW.id, DATE(NEW.dt), NEW.walk, NEW.cal, NEW.span);

END IF;

END //

DELIMITER ;

* ‘down_walk_data’에 새로운 레코드가 추가될 때마다 호출, 해당 일자의 걸음수, 칼로리, 운동시간을 합산하여 ‘down_date_walk’에 저장

o after_insert_down_risk_data

DELIMITER //

CREATE TRIGGER after_insert_down_risk_data

AFTER INSERT ON down_risk_data

FOR EACH ROW

BEGIN

DECLARE max_val INT;

SELECT risk INTO max_val FROM down_date_risk WHERE id = NEW.id AND dt = DATE(NEW.dt);

-- In case a record with the same value of 'id' & 'dt' doesn't exist in the table of 'down_date_risk',

-- it inserts a new record.

IF ROW_COUNT() = 0 THEN

INSERT INTO down_date_risk (id, risk)

VALUES (NEW.id, NEW.risk);

-- In case a record with the same value of 'id' & 'dt' exists in the table of 'down_date_risk'

-- and NEW.risk is larger than max_val, it updates 'risk' of 'down_date_risk' with 'NEW.risk'.

ELSEIF NEW.risk > max_val THEN

UPDATE down_date_risk

SET risk = NEW.risk

WHERE id = NEW.id AND dt = DATE(NEW.dt);

END IF;

END //

DELIMITER ;

* ‘down_risk_data’에 새로운 레코드가 추가될 때마다 호출, 해당 일자의 위험도 최대값을 계산하여 ‘down_date_risk’에 저장

□ DFU 진행 절차

순서	구분	내용
1	S	o DFU 개시 명령(MQTT)을 발송 o 토픽 : TS/SW2407D00001 o 명령 : Q=3;2;2;SW2407D00001;0,D1-NRF-1.0.0-240930,144125;0
2	P	o 펌웨어 다운로드(REST-API) o GET /api/sw/dfu/file/SW2407D00001
3	P	o 사용자 동의 요청 다이아로그 표시
4	P	o 사용자 동의時 DFU 시작 통보(MQTT) o 토픽 : D1 o 명령 : Q=3;2;2;SW2407D00001;1,D1-NRF-1.0.0-240930,144125;0
5	P	o 업데이트 성공時 DFU 종료 통보(MQTT) o 토픽 : D1 o 명령 : Q=3;2;2;SW2407D00001;2,D1-NRF-1.0.0-240930,144125;0
5	P	o 업데이트 실패時 DFU 오류 통보(MQTT) o 토픽 : D1 o 명령 : Q=3;2;2;SW2407D00001;4,D1-NRF-1.0.0-240930,144125;0

* 구분 : S → 서버, P → 스마트폰